﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fulcrum.ViewModelGenerator.UnitTests
{
    [TestClass]
    public class TestSampleTests
    {
        #region Helpers

        TestSample Sample { get; set; }

        [TestInitialize]
        public void Initialize()
        {
            this.Sample = new TestSample();
        }

        #endregion Helpers

        #region Properties

        [TestMethod]
        public void TestSample_Properties_VerifyDefaultValues()
        {
            Assert.AreEqual<string>("Hello, Fulcrum", this.Sample.ValidatedStringProperty);
            Assert.AreEqual<int>(10, this.Sample.ReadOnlyIntProperty);
        }

        [TestMethod]
        public void TestSample_ValidatedStringProperty_Validating_PartialMethodCalled()
        {
            string newValue = "FooBar";
            this.Sample.ValidatedStringProperty = newValue;

            Assert.IsTrue(this.Sample.OnValidatedStringPropertyValidatingImplementationCalled);
        }

        [TestMethod]
        public void TestSample_ValidatedStringProperty_Validating_IsValidFalseThrowsException()
        {
            try
            {
                this.Sample.ValidationResponse = false;
                this.Sample.ValidatedStringProperty = String.Empty;
            }
            catch (ArgumentException e)
            {
                Assert.AreEqual<string>("value", e.ParamName);
                return;
            }

            Assert.Fail();
        }

        [TestMethod]
        public void TestSample_ValidatedStringProperty_OnChanged_VerifyINotifyPropertyChanged()
        {
            bool called = false;

            string oldValue = this.Sample.ValidatedStringProperty;
            string newValue = "FooBar";

            this.Sample.ValidatedStringPropertyChanged += (o, e) =>
                {
                    if (this.Sample == o && e.OldValue == oldValue && e.NewValue == newValue)
                    {
                        called = true;
                    }
                };

            this.Sample.ValidatedStringProperty = newValue;

            Assert.IsTrue(called);
        }

        [TestMethod]
        public void TestSample_ValidatedStringProperty_OnChanged__OnPropertyChangedEvent()
        {
            bool called = false;

            string oldValue = this.Sample.ValidatedStringProperty;
            string newValue = "FooBar";

            this.Sample.ValidatedStringPropertyChanged += (o, e) =>
            {
                if (this.Sample == o && e.OldValue == oldValue && e.NewValue == newValue)
                {
                    called = true;
                }
            };

            this.Sample.ValidatedStringProperty = newValue;

            Assert.IsTrue(called);
        }

        [TestMethod]
        public void TestSample_ValidatedStringProperty_OnChanged__PartialMethodCalled()
        {
            string newValue = "FooBar";
            this.Sample.ValidatedStringProperty = newValue;

            Assert.IsTrue(this.Sample.OnValidatedStringPropertyChangedImplementationCalled);
        }

        [TestMethod]
        public void TestSample_ReadOnlyIntProperty_VerifyIsReadOnly()
        {
            var property = typeof(TestSample).GetProperty("ReadOnlyIntProperty");
            Assert.IsTrue(property.GetSetMethod(true).IsPrivate);
        }

        [TestMethod]
        public void TestSample_EqualsCompare_Same()
        {
            this.Sample.EqualsCompareProperty = 10;

            this.equalsChanged = null;
            this.Sample.EqualsComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<int>>(Sample_EqualsComparePropertyChanged);
            this.Sample.EqualsCompareProperty = 10;

            Assert.AreEqual(null, this.equalsChanged);
        }

        [TestMethod]
        public void TestSample_EqualsCompare_Different()
        {
            this.Sample.EqualsCompareProperty = 10;

            this.equalsChanged = null;
            this.Sample.EqualsComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<int>>(Sample_EqualsComparePropertyChanged);
            this.Sample.EqualsCompareProperty = 30;

            Assert.AreNotEqual(null, this.equalsChanged);
        }

        [TestMethod]
        public void TestSample_CustomCompare_Same()
        {
            this.Sample.CustomCompareProperty = "astring";

            this.customChanged = null;
            this.Sample.CustomComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_CustomComparePropertyChanged);
            this.Sample.CustomCompareProperty = "anotherstring";

            Assert.AreEqual(null, this.customChanged);
        }

        PropertyChangedEventArgs<string> customChanged = null;

        void Sample_CustomComparePropertyChanged(object sender, PropertyChangedEventArgs<string> e)
        {
            this.customChanged = e;
        }

        [TestMethod]
        public void TestSample_CustomCompare_Different()
        {
            this.Sample.CustomCompareProperty = "astring";

            this.customChanged = null;
            this.Sample.CustomComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_CustomComparePropertyChanged);
            this.Sample.CustomCompareProperty = "bstring";

            Assert.AreNotEqual(null, this.customChanged);
        }

        PropertyChangedEventArgs<int> equalsChanged;

        void Sample_EqualsComparePropertyChanged(object sender, PropertyChangedEventArgs<int> e)
        {
            this.equalsChanged = e;    
        }

        [TestMethod]
        public void TestSample_ReferenceCompare_Same()
        {
            string value = "a value";
            this.Sample.ReferenceCompareProperty = value;

            this.referenceChanged = null;
            this.Sample.ReferenceComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_ReferenceComparePropertyChanged);
            this.Sample.ReferenceCompareProperty = value;

            Assert.AreEqual(null, this.referenceChanged);
        }

        void Sample_ReferenceComparePropertyChanged(object sender, PropertyChangedEventArgs<string> e)
        {
            this.referenceChanged = e;
        }

        PropertyChangedEventArgs<string> referenceChanged = null;

        [TestMethod]
        public void TestSample_ReferenceCompare_Different()
        {
            this.Sample.ReferenceCompareProperty = "a value";

            this.referenceChanged = null;
            this.Sample.ReferenceComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_ReferenceComparePropertyChanged);
            this.Sample.ReferenceCompareProperty = String.Format("a value");

            Assert.AreNotEqual(null, this.referenceChanged);
        }

        [TestMethod]
        public void TestSample_StringCompare_Same()
        {
            this.Sample.StringCompareProperty = "a string";

            this.stringCompareChanged = null;
            this.Sample.StringComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_StringComparePropertyChanged);
            this.Sample.StringCompareProperty = "A STRING";

            Assert.AreEqual(null, this.stringCompareChanged);
        }

        void Sample_StringComparePropertyChanged(object sender, PropertyChangedEventArgs<string> e)
        {
            this.stringCompareChanged = e;
        }

        PropertyChangedEventArgs<string> stringCompareChanged = null;

        [TestMethod]
        public void TestSample_StringCompare_Different()
        {
            this.Sample.StringCompareProperty = "a string";

            this.stringCompareChanged = null;
            this.Sample.StringComparePropertyChanged += new EventHandler<PropertyChangedEventArgs<string>>(Sample_StringComparePropertyChanged);
            this.Sample.StringCompareProperty = "another string";

            Assert.AreNotEqual(null, this.stringCompareChanged);
        }

        #endregion Properties

        #region Events

        [TestMethod]
        public void TestSample_EventArgsEvent_VerifyEventHandlerType()
        {
            var @event = typeof(TestSample).GetEvent("EventArgsEvent");
            Assert.AreEqual<Type>(typeof(EventHandler), @event.EventHandlerType);
        }

        [TestMethod]
        public void TestSample_EventArgsEvent_VerifyNotify()
        {
            var eventArgs = new EventArgs();
            this.Sample.RaiseEventArgsEvent(eventArgs);

            this.Sample.EventArgsEvent += (o, e) => Assert.AreSame(eventArgs, e);
            this.Sample.RaiseEventArgsEvent(eventArgs);
        }

        [TestMethod]
        public void TestSample_NonEventArgsEvent_VerifyEventHandlerType()
        {
            var @event = typeof(TestSample).GetEvent("NonEventArgsEvent");
            
            Assert.AreEqual<Type>(typeof(EventHandler<>), @event.EventHandlerType.GetGenericTypeDefinition());
            
            Assert.AreEqual<int>(1, @event.EventHandlerType.GetGenericArguments().Count());
            Assert.AreEqual<Type>(typeof(FileSystemEventArgs), @event.EventHandlerType.GetGenericArguments().First());
        }

        [TestMethod]
        public void TestSample_NonEventArgsEvent_VerifyNotify()
        {
            var eventArgs = new FileSystemEventArgs(WatcherChangeTypes.All, String.Empty, String.Empty);
            this.Sample.RaiseNonEventArgsEvent(eventArgs);

            this.Sample.NonEventArgsEvent += (o, e) => Assert.AreSame(eventArgs, e);
            this.Sample.RaiseNonEventArgsEvent(eventArgs);
        }

        #endregion Events
    }
}
